require 'image_science'

class AdminController < ApplicationController
  session :disabled => false
  cache_sweeper :site_sweeper, :only => [:blog_submit, :photos_hide, :photos_submit, :comments_hide, :goals_submit, :goal_checkpoint_update]
  
  before_filter :ensure_admin, :except => [
    :login,
    :photos_upload
  ]
  
  def initialize
    super
    @nav = "admin_nav"
  end
  
  def index
    redirect_to :action => :blog
  end

  def login
    @nav = ""
    
    if request.post?
      # TODO: log failures
      @failed = params[:password].to_s != Auth.password
      return if @failed
      
      set_admin
      redirect_to :action => :index
    end
  end
  
  def blog
    if params[:id].to_i > 0
      @blog_edit_entry = BlogEntry.find(:first, :conditions => { :id => params[:id].to_i })
    end
    
    @blog_entries = 
      BlogEntry.get_items(5)
  end
  
  def blog_submit
    return head(404) if !request.post? && !request.xhr?
    
    entry = 
      if params[:id].to_i > 0
        BlogEntry.find(params[:id].to_i)
      else
        BlogEntry.new
      end
    entry.title = params[:title]
    entry.body  = params[:body]
    entry.remove_tags
    entry.remove_attachments
      
    if entry.save
      # TAGS 
        # Get all unique tags here.
        tags = params[:tags].to_s.split(' ').collect{ |tag| tag.downcase.strip }
        tags.uniq!
        
        # For every tag that doesn't exist, create.  Then collect all tag[id]
        tag_ids = []
        all_tags = Tag.all_by_name
        tags.each do |tag|
          if !all_tags.has_key?(tag)
            t = Tag.new(:name => tag)
            t.save
            tag_ids << t.id
          else
            tag_ids << all_tags[tag]
          end
        end
        
        # Create taggings on this blog entry.
        tag_ids.each do |id| 
          Tagging.add(id, entry)
        end
      
      # ATTACHMENTS
        attachments = Array(params[:attachments])
        attachments.each do |attachment|
          # "type,id" - ex: "PhotoSet,3"
          if !attachment.blank?
            attachment = attachment.to_s.split(',')
            
            attachable = Object.const_get(attachment[0].to_s.camelize).find(:first, :conditions => { :id => attachment[1] })
            Attachment.attach(entry, attachable) if attachable
          end
        end
      
      render :update do |page|
        page << "window.location.href = '#{target_link(entry)}';"
      end
    else
      render :update do |page|
        errors = ""
        entry.errors.each {|k,v| errors += "#{v} <br/>"}
        page.replace_html "errors-container", errors
      end
    end
  end  
  
  def get_attachables
    type = params[:type].to_s.camelize
    return head(403) if !Attachment::ATTACHABLE_TYPES.include?(type)
    
    obj_type = Object.const_get(type) rescue nil
    return head(403) if !obj_type
    
    objects = obj_type.find(:all, :order => "id desc")
    attachable_summary = objects[0,20].collect { |obj| [obj.id, obj.name] }
    
    render :json => attachable_summary
  end
  
  def photos
    @photo_sets =
      PhotoSet.get_items
      
    if params[:type].to_s == "PhotoSet" && params[:id]
      @photo_set = PhotoSet.find(params[:id].to_i)
    end
  end
  
  def photos_upload
    if params[:Filedata] && 
      (params[:Filedata].kind_of?(ActionController::UploadedTempfile) ||
       params[:Filedata].kind_of?(ActionController::UploadedStringIO))
      photo_set = 
        if params[:photo_set_id].to_i > 0
          PhotoSet.find(params[:photo_set_id].to_i)
        elsif !params[:photo_set_name].blank?
          p = PhotoSet.new({
            :name => params[:photo_set_name].to_s })
          p.save
          p
        else
          nil
        end
        
      upload = PhotoUpload.new(photo_set, params[:Filedata])
      return upload.photo ? 
        render(
          :text => { 
            :photo_set_id   => photo_set ? photo_set.id : nil,
            :id             => upload.photo.id, 
            :path           => upload.photo.path, 
            :thumbnail_path => upload.photo.path(true) 
          }.to_json) :
        head(422)
    else
      head(422)
    end
  end

  def photos_submit
    return head(404) unless request.post?
    
    photo_set = 
      params[:photo_set_id].to_i > 0 ?
        PhotoSet.find(params[:photo_set_id].to_i) :
        nil
        
    if photo_set
      photo_set.caption = params[:photo_set_caption].to_s if !params[:photo_set_caption].blank?
      photo_set.save
    end
    
    photos = {}
    photo_set.photos.each do |photo|
      photos[photo.id] = photo
    end
    
    params.keys.each do |k|
      if k.to_s =~ /^caption_for_(\d+)$/
        photo_id = $1.to_i
        photo = photos[photo_id] || Photo.find(photo_id)
        photo.caption = params[k].to_s
        photo.save
      elsif k.to_s =~ /^position_for_(\d+)$/
        photo_id = $1.to_i
        photo = photos[photo_id] || Photo.find(photo_id)
        photo.position = params[k].to_s
        photo.save
      end
    end
    
    render :update do |page|
      page << "window.location.href = '#{photos_url}';"
    end
  end

  HIDEABLE = %w(
    Photo
    Comment
  )
  def hide
    return head(404) unless request.post? and params[:id].to_i > 0 and HIDEABLE.include?(params[:type].to_s)
    
    obj = Object.const_get(params[:type].to_s).find(params[:id].to_i)
    if obj
      obj.hide
      
      element_name = 
        case params[:type].to_s
          when "Comment"
            "bar-comment-#{obj.id}"
          when "Photo"
            "photo_container_#{obj.id}"
        end
        
      render :update do |page|
        page << "$('#{element_name}').fade()"
      end
    else
        head(404)
    end
  end
  
  def goals
    if params[:id].to_i > 0
      @goal = Goal.find(:first, :conditions => { :id => params[:id].to_i })
    end

    @goals = Goal.get_items
  end
  
  def goals_submit
    return head(404) unless request.post?

    goal = 
      params[:goal_id].to_i > 0 ?
        Goal.find(params[:goal_id].to_i) :
        Goal.new
    goal.name           = params[:goal_name]
    goal.summary        = params[:goal_summary]
    goal.description    = params[:goal_description]
    goal.priority       = params[:goal_priority].to_i
    goal.begin_at       = Date.parse(params[:goal_begin_at].to_s) rescue nil
    goal.end_at         = Date.parse(params[:goal_end_at].to_s) rescue nil
    
    if (params[:goal_no_interval].to_i == 1)
      goal.interval       = nil
      goal.interval_unit  = nil
    else
      goal.interval       = params[:goal_interval].to_i
      goal.interval_unit  = params[:goal_interval_unit]
    end
      
    if goal.save
      render :update do |page|
        page << "window.location.href = '#{goals_url}';"
      end
    else
      render :update do |page|
        errors = ""
        goal.errors.each {|k,v| errors += "#{v} <br/>"}
        page.replace_html "errors-container", errors
      end
    end
  end
  
  def goals_track
    if params[:id].to_i > 0
      @goals = [ Goal.find(params[:id].to_i) ]
    else
      @goals = 
        Goal.get_items(100)
    end
    
    @completed_goals = Goal.get_completed_items
  end
  
  def goal_checkpoint_update
    return head(404) unless 
      params[:id].to_i > 0 and
      (GoalCheckpoint::STATES.include?(params[:state].to_i))
    
    if GoalCheckpoint.find(params[:id].to_i).change_state(params[:state].to_i)
      head(202)
    else
      head(403)
    end
  end
  
  def ratings
    @rateable_objects = RateableObject.get_items
  end
  
  def rating_update
    return head(404) unless 
      params[:id].to_i > 0 and
      request.post? and
      request.xhr?
      
    obj = RateableObject.find(params[:id].to_i)
    return head(404) unless obj
    
    obj.name    = params[:name].to_s
    obj.creator = params[:creator].to_s
    obj.genre   = params[:genre].to_s
    obj.url     = params[:url].to_s
    obj.rateable_type = params[:type].to_s
    obj.save
    
    head :accepted
  end
  
  def rating_remove
    return head(404) unless 
      params[:id].to_i > 0 and
      request.post? and
      request.xhr?
      
    obj = RateableObject.find(params[:id].to_i)
    obj.destroy if obj
    
    head :accepted
  end

  private
    def ensure_admin
      if !admin?
        redirect_to(:action => :login)
        return false 
      end
    end
end
